package com.jzo2o.health.handler;

import com.jzo2o.api.trade.RefundRecordApi;
import com.jzo2o.api.trade.dto.response.ExecutionResultResDTO;
import com.jzo2o.api.trade.enums.PayChannelEnum;
import com.jzo2o.common.expcetions.DBException;
import com.jzo2o.common.expcetions.ForbiddenOperationException;
import com.jzo2o.common.model.CurrentUserInfo;
import com.jzo2o.common.utils.ObjectUtils;
import com.jzo2o.health.enums.OrderPayStatusEnum;
import com.jzo2o.health.enums.OrderStatusEnum;
import com.jzo2o.health.model.UserThreadLocal;
import com.jzo2o.health.model.domain.Orders;
import com.jzo2o.health.model.domain.OrdersCancelled;
import com.jzo2o.health.model.domain.OrdersRefund;
import com.jzo2o.health.model.dto.request.OrdersCancelReqDTO;
import com.jzo2o.health.properties.OrdersJobProperties;
import com.jzo2o.health.service.IOrdersCancelService;
import com.jzo2o.health.service.IOrdersService;
import com.jzo2o.health.service.IReservationSettingService;
import com.jzo2o.health.service.OrdersRefundService;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static org.bouncycastle.asn1.x500.style.RFC4519Style.owner;

/**
 * 订单相关定时任务
 *
 * @author itcast
 * @create 2023/9/2 16:44
 **/
@Slf4j
@Component
public class OrdersHandler {

    @Resource
    private RefundRecordApi refundRecordApi;
    //解决同级方法调用，事务失效问题
//    @Resource
//    private OrdersHandler orderHandler;
    @Resource
    private OrdersJobProperties ordersJobProperties;

    /**
     * 支付超时取消订单
     * 每分钟执行一次
     */
    @XxlJob(value = "cancelOverTimePayOrder")
    public void cancelOverTimePayOrder() {

    }

    @Resource
    private IOrdersService ordersService;
    @Resource
    private IOrdersCancelService cancelService;
    @Resource
    private IReservationSettingService reservationSettingService;
    @Resource
    private ApplicationContext applicationContext;
    @Resource
    private OrdersRefundService refundService;

    /**
     * 订单退款异步任务
     */
    @XxlJob(value = "handleRefundOrders")
    public void handleRefundOrders() {
        log.info("xxljob开始处理退款订单");
        List<OrdersRefund> list = refundService.lambdaQuery().list();
        if (ObjectUtils.isEmpty(list)){
            log.info("没有需要处理退款的订单");
            return;
        }
        OrdersHandler ordersHandler = applicationContext.getBean(OrdersHandler.class);
        for (OrdersRefund ordersRefund : list) {
            ordersHandler.refundOrder(ordersRefund);
        }
    }

    /**
     * 处理订单的取消操作
     *
     * @param dto
     */
    @Transactional(rollbackFor = Exception.class)
    @Async("taskExecutor")
    public void handleOrders(OrdersCancelReqDTO dto, CurrentUserInfo currentUserInfo) {
        //判断订单是否存在
        Orders orders = ordersService.getById(dto.getId());
        if (ObjectUtils.isEmpty(orders)) {
            throw new ForbiddenOperationException("订单不存在");
        }
        if (ObjectUtils.notEqual(orders.getOrderStatus(), OrderStatusEnum.WAITING_CHECKUP.getStatus())) {
            throw new ForbiddenOperationException("订单状态不支持退款");
        }
        //修改订单状态,添加取消订单记录
        boolean update = ordersService.lambdaUpdate().eq(Orders::getId, dto.getId())
                .set(Orders::getOrderStatus, OrderStatusEnum.CLOSED.getStatus())
                .set(Orders::getPayStatus, OrderPayStatusEnum.REFUNDING.getStatus())
                .update();
        if (!update) {
            throw new DBException("取消订单失败");
        }
        OrdersCancelled ordersCancelled = new OrdersCancelled();
        ordersCancelled.setId(dto.getId());
        ordersCancelled.setCancelReason(dto.getCancelReason());
        ordersCancelled.setCancellerId(currentUserInfo.getId());
        ordersCancelled.setCancellerName(currentUserInfo.getName());
        ordersCancelled.setCancellerType(currentUserInfo.getUserType());
        ordersCancelled.setCancelTime(LocalDateTime.now());
        boolean save = cancelService.save(ordersCancelled);
        if (!save) {
            throw new DBException("添加取消订单记录失败");
        }
        //预约人数减1
        reservationSettingService.subtractOne(orders.getReservationDate());
        //添加退款记录
        OrdersRefund ordersRefund = new OrdersRefund();
        ordersRefund.setId(orders.getId());
        ordersRefund.setTradingOrderNo(orders.getTradingOrderNo());
        //ordersRefund.setRealPayAmount(orders.getSetmealPrice());
        ordersRefund.setRealPayAmount(BigDecimal.valueOf(0.01));
        ordersRefund.setCreateTime(LocalDateTime.now());
        boolean save1 = refundService.save(ordersRefund);
        if (!save1) {
            throw new DBException("添加退款记录失败");
        }

        OrdersHandler owner = applicationContext.getBean(OrdersHandler.class);
        //处理退款结果
        owner.refundOrder(ordersRefund);
    }

    /**
     * 订单退款处理
     *
     * @param ordersRefund
     */
    @Transactional(rollbackFor = Exception.class)
    public void refundOrder(OrdersRefund ordersRefund) {
        //调用远程接口退款
        ExecutionResultResDTO executionResultResDTO = null;
        try {
            executionResultResDTO = refundRecordApi.refundTrading(ordersRefund.getTradingOrderNo(), ordersRefund.getRealPayAmount());
            if (ObjectUtils.notEqual(executionResultResDTO.getRefundStatus(), OrderPayStatusEnum.REFUNDING.getStatus())){
                TimeUnit.SECONDS.sleep(3);
                executionResultResDTO = refundRecordApi.refundTrading(ordersRefund.getTradingOrderNo(), ordersRefund.getRealPayAmount());
            }

        } catch (Exception e) {
            e.printStackTrace();
            log.error("调用退款服务失败，订单号：{}", ordersRefund.getTradingOrderNo());
        }
        //处理退款结果
        if (ObjectUtils.isEmpty(executionResultResDTO)) {
            throw new ForbiddenOperationException("远程调用失败");
        }
        //修改订单状态/退款no/id /退款状态
        boolean update = ordersService.lambdaUpdate()
                .eq(Orders::getId, ordersRefund.getId())
                .set(Orders::getRefundNo, executionResultResDTO.getRefundNo())
                .set(Orders::getRefundId, executionResultResDTO.getRefundId())
                .set(Orders::getPayStatus, executionResultResDTO.getRefundStatus())
                .update();
        if (!update) {
            throw new DBException("更新订单退款信息失败");
        }
        //删除订单退款记录
        boolean b = refundService.removeById(ordersRefund.getId());
        if (!b) {
            throw new DBException("删除订单退款记录失败");
        }
    }
}
